const express = require('express');
const router = express.Router();
const debug = require('debug')('a-sokio-yun:server');
const axios = require('axios')

const mongoose = require('../db/db.js');
const deviceShe = require('../db/deviceShe')

let userMod = require('../db/userMod')
// const userLogMod = require('../db/userLogMod')

const clients = new Map();


// qywxsend("jz服务器重启")
//服务器重启,所有设备掉线
userMod.find({}).then(docs => {
    if (docs && docs.length > 0) {
        docs.forEach(doc => {
            let deviceMod = mongoose.model('device_' + doc.userName, deviceShe)
            deviceMod.updateMany({}, { taskStatus: "掉线" }, { upsert: false }).then()
        })
    }
}).catch(err => {
    console.log(err)
})

// 创建 WebSocket 路由
router.ws('/:userName/:deviceName/:device_UUID/:device_height/:device_width/:taskStatus', (ws, req) => {

    const device_dic = req.params

    // debug(device_dic)

    const deviceName = device_dic.deviceName;
    // const device_UUID = device_dic.device_UUID;
    // const device_height = device_dic.device_height;
    // const device_width = device_dic.device_width;
    const userName = device_dic.userName
    let wsid = ""
    // let userName = req.session.username;//浏览器
    // if (userName) {
    //     wsid = "liuLanQi_" + userName
    //     debug(`浏览器上线: ${wsid}`);
    // }//这个方案不知道怎么回事突然获取不到用户名
    // debug("浏览器:" + req.session.username)
    if (deviceName == "liuLanQi") {
        wsid = "liuLanQi_" + userName
        debug(`浏览器上线: ${wsid}`);
    } else {
        // 获取设备信息 并存储到数据库
        wsid = userName + "_" + deviceName
        console.log(`设备链接: ${wsid}`);
        let d = new Date() //Date.now()
        let dataStr = d.getMonth() + 1 + "月" + d.getDate() + "日" + d.getHours() + ":" + d.getMinutes() + ":" + d.getSeconds()
        //这里taskName不传

        let upData = { taskStatus: device_dic.taskStatus, socketId: wsid, updateTime: dataStr, device_width: device_dic.device_width, device_height: device_dic.device_height, device_UUID: device_dic.device_UUID }

        let deviceMod = mongoose.model('device_' + userName, deviceShe)
        deviceMod.updateOne({ deviceName }, upData, { upsert: true }).then()
    }

    // 将 WebSocket 实例存储起来
    clients.set(wsid, ws);

    // 初始化isAlive标记为true
    ws.isAlive = true;
    // 监听到信息 表示连接存活
    ws.on('pong', () => {
        // debug('收到' + wsid + '的 Pong 消息');
        ws.isAlive = true;
    });

    // 实现每隔30秒发送一次Ping消息 
    const heartbeatTimer = setInterval(() => {
        if (ws.isAlive === false) {
            console.log('服务器,' + wsid + '的心跳异常???')
            clearInterval(heartbeatTimer);
            // qywxsend('服务器,' + wsid + '的心跳异常???')
            return ws.terminate();
        }

        ws.isAlive = false;
        // debug('服务器,给' + wsid + '发送心跳包')
        ws.ping('');
    }, 30000);


    // 监听客户端连接,回调函数会传递本次连接的ws
    // 信息展示
    // 监听消息事件

    ws.on("message", msg => {
        // console.log(msg,'1111')
        // debug(`收到${wsid}的消息: ${msg}`);
        onMessage(userName, wsid, ws, msg)
    })

    // 监听关闭事件
    ws.on('close', (code, reason) => {
        // console.log("掉线");
        // 关闭心跳包检测是否存活
        clearInterval(heartbeatTimer);
        if (clients.get(wsid) !== ws) {
            console.log(`旧ws掉线: ${wsid},code:${code},reason:${reason},已重连`);
            return
        }

        clients.delete(wsid);// 从 Map 中删除 WebSocket 实例
        console.log(`ws断开: ${wsid},code:${code},reason:${reason},踢下线`);
        // 如果是投屏断开,则向手机发送取消发送截图的命令
        if (wsid == "liuLanQi_root") {
            // debug("浏览器关闭投屏:" + userName)
            for (const [id, client] of clients) {
                client.send(JSON.stringify({ type: "touPing_stop" }))
            }
        } else if (wsid.includes("liuLanQi_")) {
            // debug("浏览器关闭投屏:" + userName)
            for (const [id, client] of clients) {
                if (id.startsWith(userName + "_")) {
                    client.send(JSON.stringify({ type: "touPing_stop" }))
                }
            }
        } else {//if (wsid.indexOf("_") > -1)
            //  更新设备状态为掉线
            // qywxsend(`ws断开: ${wsid},code:${code},reason:${reason}`)
            let deviceMod = mongoose.model('device_' + userName, deviceShe)
            deviceMod.updateOne({ socketId: wsid }, { taskStatus: "掉线" }, { upsert: false }).then()
        }
    })
});

/**
 * @description: 
 * @param {*} userName 登录用户账号
 * @param {*} wsid 设备信息
 * @param {*} ws WebSocket实例
 * @param {*} msg WebSocket on('message') 监听到的数据
 * @return {*}
 */
async function onMessage(userName, wsid, ws, msg) {
    // debug(wsid, msg);

    // 判断是否二进制数据类型 如果是二进制则是投屏传输图片数据
    if (Buffer.isBuffer(msg)) {
        // debug("图片二进制数据")
        // debug("图片大小:", msg.length)
        // let wsidarr = []
        // if (userName == "root") {
        //     wsidarr = ["liuLanQi_" + userName]
        // } else {
        //     wsidarr = ["liuLanQi_" + userName, "liuLanQi_root"]
        // }
        let wsidarr = ["liuLanQi_" + userName]
        sendToClients(wsidarr, JSON.stringify({ type: "image/jpeg", wsid: wsid, binaryArr: msg }))
        return
    }

    let dic = isJSON(msg)
    if (!dic) {
        
        debug(wsid, "的消息无须解析", msg)
        return
    }
    // debug(wsid, dic);

    // 浏览器发送命令开启投屏//服务器转发给设备
    if (dic.type == "touPing_start") { // && wsid.includes("liuLanQi_")
        sendToClients(dic.socketIds, JSON.stringify({ type: "touPing_start", touPingDic: dic.touPingDic }))
    } else if (dic.type == "touPing_stop") { // 关闭投屏
        sendToClients(dic.socketIds, JSON.stringify({ type: "touPing_stop" }))
    } else if (dic.type == "startAction") { // 浏览器下发操作屏幕指令
        sendToClients(dic.wsid, JSON.stringify(dic))
    } else if (dic.type == "状态") {
        let data = dic.data
        let d = new Date() //Date.now()
        let updateTime = d.getMonth() + 1 + "月" + d.getDate() + "日" + d.getHours() + ":" + d.getMinutes() + ":" + d.getSeconds()
        let upData = { taskStatus: data.taskStatus, updateTime: updateTime, taskName: data.taskName }
        // debug("用户:" + data.userName + "的设备:" + data.deviceName + "更新状态了")
        let deviceMod = mongoose.model('device_' + data.userName, deviceShe)
        deviceMod.updateOne({ deviceName: data.deviceName }, upData, { upsert: true }).then()
    } else if (dic.type == "信息") {
        // debug("更新信息:" + dic.data);
        debug("用户:" + wsid + "更新信息")
        let deviceMod = mongoose.model('device_' + userName, deviceShe)
        deviceMod.updateOne({ socketId: wsid }, { deviceMsg: dic.data }, { upsert: true }).then()
    } else if (dic.type == "ping") {
        ws.isAlive = true;
        ws.send(JSON.stringify({ type: "pong" }))
    } else {
        console.log("无效数据");
        console.log(dic);
    }
}


// 发送数据给指定的 WebSocket 实例
function sendToClients(clientIds, data) {
    // 第一种方案
    try {
        for (const clientId of clientIds) {
            // 获取对应WebSocket实例 并传递数据
            const ws = clients.get(clientId); // set
            if (ws) {
                ws.send(data);
            }
        }
    } catch (error) {
        console.error(clientIds);
        console.error(error.toString())
    }


    // //第二种方案
    // for (const [id, ws] of clients) {
    //     if (clientIds.includes(id)) {
    //         ws.send(data);
    //     }
    // }
}


// // 发送数据给所有连接的 WebSocket 实例
// function sendToAll(data) {
//     //第一种方案
//     for (const ws of clients.values()) {
//         ws.send(data);
//     }

// }
// 判断是否为json格式 如果解析后数据为obj且不为空 则正常返回数据
function isJSON(str) {
    if (typeof str == 'string') {
        try {
            var obj = JSON.parse(str);
            if (typeof obj == 'object' && obj) {
                return obj;
            } else {
                return false;
            }
        } catch (e) {
            debug(e)
            return false;
        }
    } else {
        console.log(typeof str + "????????????????????????");
    }
}


// // 解析请求体
// router.use(bodyParser.json());
// router.use(bodyParser.urlencoded({ extended: true }));

// 处理 HTTP POST 请求

// 判断用户是否在线 在线得话 开始使用WebScoket向脚本发送任务
router.post('/faTast', (req, res) => {
    let { data } = req.body
    // debug("data", req.body)
    // let userName = data.userName
    if (data.userName) {
        faTask(res, data, data.userName)
    } else {
        res.json({
            code: -1,
            msg: "失败:用户登录失效"
        })
    }
})

async function faTask(res, data, userName) {
    //向后台发送给提交成功
    debug("服务器收到任务,开始分发")
    //给设备arr发任务,并记录日志
    try {//data.taskData.taskId 是多任务处理

        // debug("data.taskData.taskID", data.taskData.taskID)
        // debug(data.taskData.taskID ? { taskID: data.taskData.taskID } : data.taskData)
        // debug(data.taskData.taskID || data.taskData)

        let taskTask = JSON.stringify({ type: "deviceTask", serverData: { taskName: data.taskName, taskData: data.taskData?.taskID || data.taskData, timeStamp: data.timeStamp } })
        let wsIds = [] // 定义一个数组，用于保存要发送到的WebSocket客户端的ID
        if (data.socketIdArr && data.socketIdArr.length > 0) {
            debug('有附加设备')
            wsIds = data.socketIdArr
        }

        if (data.groupDocArr && data.groupDocArr.length > 0) {
            // debug('有分组全选')
            // debug(data.groupDocArr)
            let deviceMod = mongoose.model('device_' + userName, deviceShe)
            for (let groupDoc of data.groupDocArr) {
                // debug(groupDoc)
                let devices = await deviceMod.find({ groupId: groupDoc.groupId })//.exec()
                for (let device of devices) {
                    //给指定得客户端发送消息1
                    // debug("添加到任务数组:用户的" + userName + "[" + groupDoc.groupName + "]组的:" + device.deviceName + ",wsid:" + device.socketId)
                    if (!wsIds.includes(device.socketId)) {
                        await wsIds.push(device.socketId)
                    }
                };
            }
        }

        //记录日志
        // let d = new Date()
        // debug(userObj)
        // new userLogMod({
        //     userName: userName,
        //     logStr: "所选设备[" + wsIds + "],任务名[" + data.taskName + "],任务参数[" + JSON.stringify(data.taskData) + "]",
        //     logTime: d.getFullYear() + "年" + (d.getMonth() + 1) + "月" + d.getDate() + "日" + d.getHours() + ":" + d.getMinutes() + ":" + d.getSeconds()
        // }).save()

        //发送任务
        debug("下发任务给wsIds", wsIds)
        sendToClients(wsIds, taskTask)
        res.json({
            code: 1,
            msg: "成功"
        })
    } catch (err10) {
        res.json({
            code: -1,
            msg: "下发任务出错:" + err10.toString()
        })
    }
}

router.post('/send/:clientId', (req, res) => {
    const clientId = req.params.clientId; // 获取URL路径中的clientId参数
    const data = req.body.data; // 获取请求体中的data字段

    debug(`Sending data to: ${clientId}`); // 打印日志，表示正在向指定的clientId发送数据
    debug(`Data: ${data}`); // 打印日志，表示要发送的数据内容

    // 发送数据
    sendToClients([clientId], data); // 调用sendToClients()方法，将数据发送给指定的clientId
    res.sendStatus(200);// 返回状态码200表示成功处理请求
});

router.get('/wss', function (req, res) {
    let zhangHao = req.query.z // 获取查询参数中的账号（用户名）
    if (zhangHao) { // 如果账号存在
        let deviceNum = 0 // 已上线设备数量
        for (const id of clients.keys()) { // 判断连接ID是否以当前账号开头
            if (id.startsWith(zhangHao + "_")) { // 判断连接ID是否以当前账号开头
                deviceNum = deviceNum + 1 // 判断连接ID是否以当前账号开头
            }
        }
        res.send(`ws(${zhangHao}):${deviceNum}个`) // 返回格式化的已上线设备数量信息
    } else {
        res.send(`ws(总):${clients.size}个`) // 如果账号不存在，返回格式化的总连接数量信息
    }
});

//上线前先检测
router.get('/wsid', async function (req, res) {
    let deviceName = req.query.id
    let userName = req.query.userName
    let wsid = `${userName}_${deviceName}`
    console.log(wsid);
    try {
        //先判断有没有此账户,再判断上线数量,最后判断有没有重复
        const doc = await userMod.findOne({ userName })
        if (!doc) {
            // debug(userName + "用户不存在");
            return res.json({
                code: -1,
                msg: "用户不存在"
            })
        }

        //用户存在
        //判断上线数量两种方案,(暂用第二种)
        //第一种通过数据库判断,缺点1占用数据库线程.缺点2需要把没用的设备删除
        //第二种通过遍历ws,例如root,通过di是否indexOf("root_")然后+1来计算.缺点遍历完才知道个数.占用内存?

        let deviceNum = 0 // 已上线设备数量
        const maxNum = doc.userDeviceNum // 设定的此用户占控数量
        debug(`本次上线id(${wsid}),用户(${userName})的最大占控数量${maxNum}个`)
        const wwwsss = clients.get(wsid) // 根据连接ID获取已存在的连接对象
        if (wwwsss) { // 如果连接ID已存在的连接对象
            console.log(`连接ID${wsid}已存在的连接对象,关闭先前的连接`)
            wwwsss.terminate(); // 关闭先前的连接
            // throw new Error(wsid + "有重复")
            return res.json({
                code: -1,
                msg: "疑似重复,已剔除老设备"
            })
        }

        for (const id of clients.keys()) {
            console.log("id", id);
            if (id.startsWith(userName + "_")) { // 判断连接ID是否以当前用户名开头
                deviceNum = deviceNum + 1 // 计算已上线设备数量
            }
        }


        debug(userName + ':已有设备数量:' + deviceNum)

        if (deviceNum >= maxNum) {  // 如果已上线设备数量超过设定的上限
            return res.json({
                code: -1,
                msg: `设备超过设定数量:${maxNum}`
            })
        } else {
            return res.json({
                code: 1,
                msg: "可以上线"
            })
        }
    } catch (error) {
        return res.json({
            code: -1,
            msg: "服务器:" + error.message
        })
    }

})
//手机端ws验证代码
// function yanZheng() {
//     // for (let i = 3; i > 0; i--) {
//     // while (true) {
//     logd("验证中..",)
//     try {
//         let resJson = http.get("http://" + server_api + "/wsRouter/wsid?userName=" + jz_yun.云控账号 + "&id=" + jz_yun.云控编号).body.json()
//         if (resJson) {
//             // logd(JSON.stringify(resJson))
//             if (resJson.code == 1) {
//                 // logd("验证成功.连接云控后台中..")
//                 return true
//             } else {
//                 // loge(resJson.msg, "20秒后重试")
//                 loge(resJson.msg)
//                 alert(resJson.msg + ",请重试")
//                 exit()
//             }
//         } else {
//             logi("登录错误,重试中")
//             // exit()
//         }
//     } catch (error) {
//         loge("验证错误:", error)
//         // alert("验证错误:【" + error.toString() + "】行:" + error.lineNumber)
//         // exit()
//     }
//     sleep(20000)
//     // }

// }

async function qywxsend(str) {
    try {
        let response = await axios.post("https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=d817ae9d-ed16-46d4-bf2a-cdcfc8ff50d0", {
            msgtype: 'text',
            text: { content: str }
        })
        if (response.data.errmsg == "ok") {
            // log.info("企微发信成功")
            return true
        }
    } catch (error) {
        log.error("企微发信错误:", error)
    }
}

module.exports = { router, clients };
